home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Misc / a2 / Source / jump.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-21  |  7.9 KB  |  323 lines

  1. /*
  2.  *  a2, an Apple II emulator in C
  3.  *  (c) Copyright 1990 by Rich Skrenta
  4.  *
  5.  *  Command line interface written by Tom Markson
  6.  *
  7.  *  Distribution agreement:
  8.  *
  9.  *    You may freely copy or redistribute this software, so long
  10.  *    as there is no profit made from its use, sale, trade or
  11.  *    reproduction.  You may not change this copyright notice,
  12.  *    and it must be included prominently in any copy made.
  13.  *
  14.  *  Send emulator related mail to:  skrenta@blekko.commodore.com
  15.  *                    skrenta@blekko.uucp
  16.  */
  17.  
  18.  
  19. #import    <stdio.h>
  20. #import    <libc.h>
  21. #import    <fcntl.h>
  22. #import    <ctype.h>
  23. #import    "a2.h"
  24.  
  25. #define        jump_check(a,b,c,d)    (mem[Pc]==a && mem[Pc+1]==b && mem[Pc+2]==c && mem[Pc+3]==d)
  26.  
  27. /*
  28.  *  In order to improve performance, we intercept the PC on JSR's
  29.  *  and JMP's to certain locations and handled the intended function
  30.  *  in C instead of letting the emulator interpret 6502.
  31.  *
  32.  *  This is done for video output, to produce an acceptable scroll;
  33.  *  for the boot prom, so it crashes if there is no disk in the drive;
  34.  *  and for other miscellaneous routines such as WAIT for speed.
  35.  *
  36.  *  In most cases the interceptor routine checks to see if the code it's
  37.  *  intercepting looks like what it thinks should be there; it doesn't
  38.  *  snatch the PC if the first four bytes of the routine don't match.
  39.  */
  40.  
  41.  
  42. #define        I_WAIT        1    /* defeat ROM WAIT routine           */
  43. #define        I_PRODOS    2    /* Prodos high level intercept       */
  44. #define        I_RWTS        3    /* DOS 3.3 high-level intercept      */
  45. #define        I_BELL        4    /* don't toggle C030, output a bell  */
  46. #define        I_VIDOUT    5    /* speeds up scrolling tremendously  */
  47. #define        I_BOOT        6    /* crash if no disk on boot          */
  48. #define        I_BOOTWAIT    7    /* defeat delay loops in DOS boot    */
  49. #define        I_BOOTPATCH    8    /* patch dos for fast raw access     */
  50.  
  51.  
  52. extern int map_to_upper;
  53. extern unsigned char disk_ref();
  54.  
  55. static int key_clear = TRUE;
  56. static unsigned char last_key = 0;
  57. static unsigned char temp_key;
  58.  
  59. void set_c0( unsigned short a, unsigned char n)
  60. {
  61.   
  62.   switch (a & 0xFF) {
  63.   case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15:
  64.   case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B:
  65.   case 0x1C: case 0x1D: case 0x1E: case 0x1F:
  66.     key_clear = TRUE;
  67.     last_key &= 0x7F;
  68.     break;
  69.     
  70.   case 0x80: case 0x81: case 0x82: case 0x83:
  71.   case 0x88: case 0x89: case 0x8A: case 0x8B:
  72.     ram_card(a);
  73.     break;
  74.     
  75.     /*
  76.      *  Slot 6 Disk II memory map 
  77.      */
  78.     
  79. #ifdef STUFFY_TURTLE
  80.   case 0xC0E0: case 0xC0E1: case 0xC0E2: case 0xC0E3:
  81.   case 0xC0E4: case 0xC0E5: case 0xC0E6: case 0xC0E7:
  82.   case 0xC0E8: case 0xC0E9: case 0xC0EA: case 0xC0EB:
  83.   case 0xC0EC: case 0xC0ED: case 0xC0EE: case 0xC0EF:
  84. #endif
  85.   case 0xE0: case 0xE1: case 0xE2: case 0xE3:
  86.   case 0xE4: case 0xE5: case 0xE6: case 0xE7:
  87.   case 0xE8: case 0xE9: case 0xEA: case 0xEB:
  88.   case 0xEC: case 0xED: case 0xEE: case 0xEF:
  89.     disk_ref(a, n);
  90.     break;
  91.     
  92.   default:
  93.     mem[a] = n;
  94.   }
  95. }
  96.  
  97. void set_special_jumps(void)
  98. {
  99.   mem[0x43] = 0x60;            /* for ProDos boot */
  100.   
  101.   jmp_tbl[0xBD00] = I_RWTS;
  102.   jmp_tbl[0xC600] = I_BOOT;
  103.   jmp_tbl[0xC680] = I_PRODOS;    /* patched into boot prom below */
  104.   jmp_tbl[0x9D84] = I_BOOTPATCH;    /* fast raw dos access */
  105.   jmp_tbl[0xFBD9] = I_BELL;
  106.   jmp_tbl[0xFBFD] = I_VIDOUT;
  107.   jmp_tbl[0xFCA8] = I_WAIT;
  108.   
  109.   jmp_tbl[0x3A00] = I_BOOTWAIT;
  110.   
  111.   mem_set[0xC0] = set_c0;
  112.   mem_set[0xC6] = set_writep;    /* write protect disk prom */
  113.   
  114. #if 0
  115.   mem[0xC600] = 0;        /* flag for boot interception */
  116.   mem[0xC601] = 0x20;        /* disk prom magic number */
  117.   mem[0xC603] = 0x00;
  118.   mem[0xC605] = 0x03;
  119.   mem[0xC607] = 0x3C;
  120. #endif
  121.   
  122.   /*
  123.    *  Patch boot rom for fake Prodos driver
  124.    */
  125.   
  126.   mem[0xC6FF] = 0x80;        /* C680 is driver address */
  127.   mem[0xC6FE] = 0x1F;        /* info about device */
  128.   
  129.   screen_setup();
  130. }
  131.  
  132.  
  133. void jump(int key)
  134. {
  135.   switch (key) {
  136.   case I_WAIT:                    /* FCA8 */
  137.     if (jump_check(0x38, 0x48, 0xE9, 0x01)) {
  138.       A = 0;
  139.       N = 0;
  140.       V = 0;
  141.       C = 1;
  142.       DO_RTS;
  143.     }
  144.     break;
  145.     
  146.   case I_PRODOS:                    /* C680 */
  147.     prodos();
  148.     break;
  149.     
  150.   case I_RWTS:                    /* BD00 */
  151.     if (jump_check(0x84, 0x48, 0x85, 0x49))
  152.       rwts();
  153.     break;
  154.     
  155.   case I_BELL:                    /* FBD9 */
  156.     if (jump_check(0x60, 0x87, 0xD0, 0x12)) {
  157.       putchar(7);
  158.       fflush(stdout);
  159.       DO_RTS;
  160.     }
  161.     break;
  162.     
  163.   case I_VIDOUT:                    /* FBFD */
  164.     if (jump_check(0xC9, 0xA0, 0xB0, 0xEF))
  165.       vidout();
  166.     break;
  167.     
  168.   case I_BOOT:                    /* C600 */
  169.     if (disk[0] < 0) {
  170.       info("boot: no disk");
  171.       PCINC;            /* BRK into the monitor */
  172.       push(high(Pc));
  173.       push(low(Pc));
  174.       B = 1;
  175.       push(get_status());
  176.       Pc = mem[0xFFFE] | (mem[0xFFFF] << 8);
  177.       return;
  178.     }
  179.     info("boot");
  180.     
  181.     /* 
  182.      *  We read the second half of a 512 byte block in case we're
  183.      *  booting something that depends on this being a newer boot prom
  184.      */
  185.     
  186.     drive = 0;
  187.     read_disk(0, 14, &mem[0x900]);
  188.     break;
  189.     
  190.     /*
  191.      *  Standard DOS 3.3 has some pretty gross delay loops in its
  192.      *  boot code.  The following patches defeat two of them.
  193.      *  This could be dangerous; it seems to work, but DOS's original
  194.      *  side effects are not maintained.  Comment out the jmp_tbl assignment
  195.      *  of I_BOOTWAIT above if you are distrustful.
  196.      *
  197.      *  Interesting.  Dos relocates the patches when it moves into higher
  198.      *  memory.  If you boot with a fast-booting dos that doesn't have the
  199.      *  delays at 3A00, but still has them at BA00 & BD9E when it starts
  200.      *  up, it will be slow if you turn off RWTS interception and use the
  201.      *  raw interface.  However, slow-booting real DOS that gets patched
  202.      *  while it's booting will have a faster raw interface, since it
  203.      *  relocated the patches...
  204.      */
  205.     
  206.   case I_BOOTWAIT:                /* 3A00 */
  207.     if (jump_check(0xA2, 0x11, 0xCA, 0xD0)) {
  208.       mem[0x3A00] = 0x60;        /* RTS */
  209.       if (mem[0x3D9E] == 0xA0
  210.       &&  mem[0x3D9F] == 0x12
  211.       &&  mem[0x3DA0] == 0x88) {
  212.     mem[0x3D9E] = 0x4C;    /* JMP past it */
  213.     mem[0x3D9F] = 0xAB;
  214.     mem[0x3DA0] = 0x3D;    /* gets relocated */
  215.       }
  216.     }
  217.     break;
  218.     
  219.     /*
  220.      *  This one is unnecessary since we do high-level RWTS interception
  221.      */
  222.     
  223.   case I_BOOTPATCH:                /* 9D84 */
  224.     if (jump_check(0xAD, 0xE9, 0xB7, 0x4A)) {
  225.       if (mem[0xBA00] == 0xA2
  226.       &&  mem[0xBA01] == 0x11
  227.       &&  mem[0xBA02] == 0xCA) {
  228.     mem[0xBA00] = 0x60;        /* RTS */
  229.     if (mem[0xBD9E] == 0xA0
  230.         &&  mem[0xBD9F] == 0x12
  231.         &&  mem[0xBDA0] == 0x88) {
  232.       mem[0xBD9E] = 0x4C;
  233.       mem[0xBD9F] = 0xAB;
  234.       mem[0xBDA0] = 0xBD;
  235.     }
  236.       }
  237.     }
  238.     break;
  239.     
  240.   default:
  241.     fprintf(stderr, "bad jump intercept key: %d\n", key);
  242.     assert(FALSE);
  243.   }
  244. }
  245.  
  246.  
  247. extern int save_flags;
  248.  
  249. unsigned char
  250.   mem_map(a)
  251. unsigned short a;
  252. {
  253.   
  254.   switch (a) {
  255.   case 0xC000:
  256.     if (key_clear) {
  257.       fcntl (0, F_SETFL, save_flags | O_NDELAY);
  258.       
  259.       if (read (0, &temp_key, 1) == 1) {
  260.     key_clear = FALSE;
  261.     if (temp_key == '\n')
  262.       temp_key = '\r';
  263.     else if (temp_key == 127)
  264.       temp_key = 8;
  265.     if (map_to_upper)
  266.       temp_key = toupper(temp_key);
  267.     last_key = temp_key | 0x80;
  268.       }
  269.       
  270.       fcntl (0, F_SETFL, save_flags);
  271.     }
  272.     return(last_key);
  273.     
  274.   case 0xC010:
  275.     key_clear = TRUE;
  276.     last_key &= 0x7F;
  277.     return(0);            /* what should this be? */
  278.     
  279.   case 0xC011:
  280.     if (bank2_enable)
  281.       return(0xFF);
  282.     return(0x00);
  283.     
  284.   case 0xC012:
  285.     if (ram_read)
  286.       return(0xFF);
  287.     return(0x00);
  288.     
  289.   case 0xC080: case 0xC081: case 0xC082: case 0xC083:
  290.   case 0xC088: case 0xC089: case 0xC08A: case 0xC08B:
  291.     ram_card(a);
  292.     return(0x00);
  293.     
  294.     /*
  295.      *  Slot 6 Disk II memory map 
  296.      */
  297.     
  298.   case 0xC0E0: case 0xC0E1: case 0xC0E2: case 0xC0E3:
  299.   case 0xC0E4: case 0xC0E5: case 0xC0E6: case 0xC0E7:
  300.   case 0xC0E8: case 0xC0E9: case 0xC0EA: case 0xC0EB:
  301.   case 0xC0EC: case 0xC0ED: case 0xC0EE: case 0xC0EF:
  302.     return( disk_ref(a, 0) );
  303.     
  304. #if 0
  305.     /*
  306.      *  Keep the boot prom magic number from appearing if there is
  307.      *  no disk in the drive
  308.      */
  309.     
  310.   case 0xC600:
  311.   case 0xC601:
  312.     if (disk[0] < 0)
  313.       return(0);
  314.     break;
  315. #endif
  316.     
  317.   }
  318.   
  319.   return(mem[a]);        /* default */
  320. }
  321.  
  322.  
  323.